package com.onlygx.dva.common.utils;


import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Maps;
import com.onlygx.dva.common.constant.UserConstant;
import com.onlygx.dva.common.entity.dto.CoreUserDTO;
import com.onlygx.dva.common.exception.FailRequestException;
import org.slf4j.Logger;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 描述 : 请求工具类
 * 作者 : GaoXiang
 * 时间 : 19-12-17
 * 版本 : V1.0
 */
public class RequestLogUtil {

    /**
     * 从header中获取用户信息
     * 时间 2021年12月29日13:54:06 创建 高祥
     */
    public static CoreUserDTO getRequestUser(HttpServletRequest request){
        String currentUserHeader = request.getHeader(UserConstant.CURRENT_USER);

        if(StrUtil.isEmpty(currentUserHeader)){
            throw new FailRequestException("Header中没有发现用户信息");
        }

        if(StrUtil.isNotEmpty(currentUserHeader)){
            try {
                return JSONUtil.toBean(Base64.decodeStr(currentUserHeader), CoreUserDTO.class);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
        return null;
    }

    public static void printRequestErrorInfo(Logger logger, HttpServletRequest request, Exception e){
        //链路追踪
        String agent = request.getHeader("Traceparent");
        OpenTelemetryLogUtils.showError(agent,"异常日志：" + e.getMessage());

        logger.error("================== 「拦截到异常信息」「BEGIN」 ==================");
        printRequest(logger, request);
        logger.error("异常详情：" + e.toString());
        logger.error("异常信息：" + e.getMessage());
        // 默认错误异常打印
        //e.printStackTrace();
        // 自定义异常打印
//        StackTraceElement[] stackArray = e.getStackTrace();
//        logger.error("异常描述：" + stackArray[0].toString());
//        IntStream.range(0, stackArray.length).forEach(i -> {
//            StackTraceElement element = stackArray[i];
//            logger.error("异常详情[" + i + "]：" + element.toString());
//        });
        logger.error("================== 「拦截到异常信息」「E N D」 ==================");
    }

    public static void printRequest(Logger logger, HttpServletRequest request) {
        logger.error("资源路径：" + request.getServletPath());
        logger.error("请求参数：" + request.getQueryString());
        logger.error("请求表单：" + JSONUtil.toJsonStr(request.getParameterMap()));
        logger.error("请求实体：" + getRequestBody(logger,request));
        logger.error("请求协议：" + request.getScheme()  + " - " + request.getProtocol());
        logger.error("请求方式：" + request.getMethod());
        logger.error("请求编码：" + request.getCharacterEncoding());
        logger.error("请求格式：" + request.getContentType());
        logger.error("请求大小：" + request.getContentLength());
        logger.error("请求地址：" + request.getRemoteAddr());
        logger.error("目标主机：" + request.getServerName());
        logger.error("目标端口：" + request.getServerPort());
    }


    /**
     * 打印请求体
     * 2023年7月28日09:28:51 高祥
     */
    public static String getRequestBody(Logger logger,ServletRequest request) {
        StringBuilder sb = new StringBuilder();
        try (ServletInputStream inputStream = request.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            //e.printStackTrace();
            logger.error("获取参数失败：" + e.getMessage() + " 请检查请求格式是否为：application/json");
        }
        //过滤无意义空格，但保留\s
        return sb.toString().replaceAll("[\\t\\n\\r]","");
    }

    /**
     * 获取ip
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }


    public static String getURI(HttpServletRequest request){
        return request.getRequestURI();
    }

    public static String getURL(HttpServletRequest request){
        return request.getRequestURL().toString();
    }

    /**
     * 获取key值获取request中的value
     */
    public static String getParam(HttpServletRequest request,String key){
        return request.getParameter(key);
    }

    /**
     * 获取request请求的map
     */
    public static Map<String, String> getRequestMap(HttpServletRequest req) {
        Map<String, String> params = Maps.newHashMap();
        Map<String, String[]> requestParams = req.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        return params;
    }

    /**
     * 获取请求连接参数
     *
     */
    public static String getRequestStr(HttpServletRequest req, String excludeStr) {
        StringBuilder buffer = new StringBuilder();
        Map<String, String[]> requestParams = req.getParameterMap();
        for (String name : requestParams.keySet()) {
            if (name.equals(excludeStr)) {
                continue;
            }
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            buffer.append(name).append("=").append(valueStr).append("&");
        }

        if (buffer.length() > 0) {
            buffer.deleteCharAt(buffer.length() - 1);
        }
        return buffer.toString();
    }

    /**
     * 添加请求连接参数
     *
     */
    public static String getOrderRequestStr(HttpServletRequest req, String excludeStr){
        List<String> list = new ArrayList<String>();
        Map<String, String[]> requestParams = req.getParameterMap();
        for (String name : requestParams.keySet()) {
            if (name.equals(excludeStr)) {
                continue;
            }
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            list.add(name + "=" + valueStr);
        }
        StringBuilder buffer = new StringBuilder();
        if(list.size()>0){
            Collections.sort(list);
            for (int i = 0; i <list.size() ; i++) {
                buffer .append( (i == list.size() - 1) ?  list.get(i) : list.get(i) + "&");
            }
        }
        return buffer.toString();
    }



    public static String getOrderStr(Map<String,String> map, String excludeStr){
        List<String> list = new ArrayList<String>();
        for (String name : map.keySet()) {
            if (name.equals(excludeStr)) {
                continue;
            }
            String value = map.get(name);
            list.add(name + "=" + value);
        }
        StringBuilder buffer = new StringBuilder();
        if(list.size()>0){
            Collections.sort(list);
            for (int i = 0; i <list.size() ; i++) {
                buffer .append( (i == list.size() - 1) ?  list.get(i) : list.get(i) + "&");
            }
        }
        return buffer.toString();
    }


    public static String getUriPath(HttpServletRequest req) {
        String uri = req.getRequestURI();
        String contextPath = req.getServletContext().getContextPath();
        if (!StrUtil.isEmpty(contextPath)) {
            uri = uri.replaceFirst(contextPath, "");
        }
        return uri;
    }

}
